#include "stdafx.h"
#include "../aclib/HexParser.h"
#include "../aclib/BlockData.h"

namespace AC = AppliedCryptography;
using ::testing::Return;

TEST(BlockData, Delete)
{
	AC::HexParser hx;
	AC::BlockData<3> bd1(hx("0102030405060708090A"));
	AC::BlockData<3> bd2(hx("0102030405060708090A"));
	AC::BlockData<3> bd3(hx("0102030405060708090A"));
	AC::Block<3> block;

	EXPECT_TRUE(bd3.At(0) == block.Set(hx("010203")));
	EXPECT_TRUE(bd3.At(1) == block.Set(hx("040506")));
	EXPECT_TRUE(bd3.At(2) == block.Set(hx("070809")));
	EXPECT_TRUE(bd3.At(3) == block.Set(hx("0A0000")));
	EXPECT_EQ(4, bd3.Blocks());
	EXPECT_EQ(1, bd3.LastBlockLength());
	EXPECT_EQ(10, bd3.Size());

	// Delete first block
	bd1.Delete(0);
	EXPECT_TRUE(bd1.At(0) == block.Set(hx("040506"))) << hx(bd1.At(0).Get()).c_str();
	EXPECT_TRUE(bd1.At(1) == block.Set(hx("070809"))) << hx(bd1.At(1).Get()).c_str();
	EXPECT_TRUE(bd1.At(2) == block.Set(hx("0A0000"))) << hx(bd1.At(2).Get()).c_str();
	EXPECT_EQ(3, bd1.Blocks());
	EXPECT_EQ(1, bd1.LastBlockLength());
	EXPECT_EQ(7, bd1.Size());
	EXPECT_THROW(bd1.At(3), AC::Exception);

	// Delete middle block
	bd2.Delete(2);
	EXPECT_TRUE(bd2.At(0) == block.Set(hx("010203")));
	EXPECT_TRUE(bd2.At(1) == block.Set(hx("040506")));
	EXPECT_TRUE(bd2.At(2) == block.Set(hx("0A0000")));
	EXPECT_EQ(3, bd2.Blocks());
	EXPECT_EQ(1, bd2.LastBlockLength());
	EXPECT_EQ(7, bd2.Size());
	EXPECT_THROW(bd2.At(3), AC::Exception);

	// Delete last block
	bd3.Delete(3);
	EXPECT_TRUE(bd3.At(0) == block.Set(hx("010203")));
	EXPECT_TRUE(bd3.At(1) == block.Set(hx("040506")));
	EXPECT_TRUE(bd3.At(2) == block.Set(hx("070809")));
	EXPECT_EQ(3, bd3.Blocks());
	EXPECT_EQ(3, bd3.LastBlockLength());
	EXPECT_EQ(9, bd3.Size());
	EXPECT_THROW(bd3.At(3), AC::Exception);
};

TEST(BlockData, ShortBlockCount)
{
	AC::HexParser hx;
	AC::BlockData<1> bdata(hx("010203040506"));

	EXPECT_EQ(bdata.Blocks(), 6);
};

TEST(BlockData, LargeBlockCount)
{
	AC::HexParser hx;
	AC::BlockData<3> bdata(hx("010203040506"));

	EXPECT_EQ(bdata.Blocks(), 2);
};

TEST(BlockData, BlockSizeNotAlignCount)
{
	AC::HexParser hx;
	AC::BlockData<3> bdata(hx("01020304050607"));

	ASSERT_NO_THROW({EXPECT_EQ(bdata.Blocks(), 3);});
};

TEST(BlockData, LastBlockNotAlign)
{
	AC::HexParser hx;
	AC::BlockData<4> bdata(hx("010203040506"));
	AC::Block<4> block;

	ASSERT_NO_THROW({EXPECT_TRUE(bdata.At(0) == block.Set(hx("01020304")));});
	EXPECT_TRUE(bdata.At(1) == block.Set(hx("05060000")));
};

TEST(BlockData, LastBlockSize)
{
	AC::HexParser hx;
	AC::BlockData<1> bdata1(hx("01020304050607"));
	AC::BlockData<3> bdata2(hx("01020304050607"));
	AC::BlockData<4> bdata3(hx("0102030405060708090A0B"));
	AC::BlockData<4> bdata4(hx("0102030405060708"));

	EXPECT_EQ(bdata1.LastBlockLength(), 1);
	EXPECT_EQ(bdata2.LastBlockLength(), 1);
	EXPECT_EQ(bdata3.LastBlockLength(), 3);
	EXPECT_EQ(bdata4.LastBlockLength(), 4);
};

TEST(BlockData, ShortBlockAtIndex)
{
	AC::HexParser hx;
	AC::BlockData<1> bdata(hx("010203040506"));
	AC::Block<1> block;

	EXPECT_TRUE(bdata.At(0) == block.Set(hx("01")));
	EXPECT_TRUE(bdata.At(1) == block.Set(hx("02")));
	EXPECT_TRUE(bdata.At(2) == block.Set(hx("03")));
	EXPECT_TRUE(bdata.At(3) == block.Set(hx("04")));
	EXPECT_TRUE(bdata.At(4) == block.Set(hx("05")));
	EXPECT_TRUE(bdata.At(5) == block.Set(hx("06")));

	EXPECT_THROW(bdata.At(6), AC::Exception);
};

TEST(BlockData, LargeBlockAtIndex)
{
	AC::HexParser hx;
	AC::BlockData<3> bdata(hx("010203040506"));
	AC::Block<3> block;

	EXPECT_TRUE(bdata.At(0) == block.Set(hx("010203")));
	EXPECT_TRUE(bdata.At(1) == block.Set(hx("040506")));

	EXPECT_THROW(bdata.At(2), AC::Exception);
};
